//////////////////////////////////////////////////////////////////
// MattiseOS Kernel
// Date: 2008
// Author: Matthew Iselin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////

// Includes
#include <mattise.h>
#include <stdint.h>
#include <core/dts.h>
#include <mem/util.h>

// Macros
#define ISR_FUNCTION( num ) isr_##num

// Prototypes

// loads the IDTR
void idt_flush( uint32_t ptr );

// all the exception handler ISRs
void isr_0();
void isr_1();
void isr_2();
void isr_3();
void isr_4();
void isr_5();
void isr_6();
void isr_7();
void isr_8();
void isr_9();
void isr_10();
void isr_11();
void isr_12();
void isr_13();
void isr_14();
void isr_15();
void isr_16();
void isr_17();
void isr_18();
void isr_19();
void isr_20();
void isr_21();
void isr_22();
void isr_23();
void isr_24();
void isr_25();
void isr_26();
void isr_27();
void isr_28();
void isr_29();
void isr_30();
void isr_31();
void isr_128();

// Variables

// the IDT
static struct idt_entry kIdt[256];

// the IDT pointer
static struct idt_ptr kIdtPtr;

// Functions

// sets a gate in the IDT
void kIdtSetGate( uint32_t num, uint32_t base, uint16_t sel, uint8_t flags )
{
	// check the number given - because it's unsigned we know it'll never be lower than 0
	if( num >= 256 )
		return;

	// setup the base
	kIdt[num].base_lo = base & 0xFFFF;
	kIdt[num].base_hi = (base >> 16) & 0xFFFF;

	// setup the selector, reserved bits, and flags
	kIdt[num].sel = sel;
	kIdt[num].always0 = 0;
	kIdt[num].flags = flags | 0x60; // ORing by 0x60 sets the privilege level to 3
}

// initializes the IDT
void kInitIDT()
{
	// setup the IDT pointer
	kIdtPtr.limit = (sizeof( struct idt_entry ) * 256) - 1;
	kIdtPtr.base = (uint32_t) &kIdt;

	// map in the IDT with user privileges
	MapPage( 0xFFFFF000, (uint32_t) kIdt, (uint32_t) kIdt, PF_PRESENT | PF_READWRITE | PF_USER | PF_KERNELPAGE | PF_IMMUTABLE );

	// zero out the IDT
	memset( kIdt, 0, sizeof( struct idt_entry ) * 256 );

	// set all the ISRs
	kIdtSetGate( 0, (uint32_t) isr_0, 0x08, 0x8E );
	kIdtSetGate( 1, (uint32_t) isr_1, 0x08, 0x8E );
	kIdtSetGate( 2, (uint32_t) isr_2, 0x08, 0x8E );
	kIdtSetGate( 3, (uint32_t) isr_3, 0x08, 0x8E );
	kIdtSetGate( 4, (uint32_t) isr_4, 0x08, 0x8E );
	kIdtSetGate( 5, (uint32_t) isr_5, 0x08, 0x8E );
	kIdtSetGate( 6, (uint32_t) isr_6, 0x08, 0x8E );
	kIdtSetGate( 7, (uint32_t) isr_7, 0x08, 0x8E );
	kIdtSetGate( 8, (uint32_t) isr_8, 0x08, 0x8E );
	kIdtSetGate( 9, (uint32_t) isr_9, 0x08, 0x8E );
	kIdtSetGate( 10, (uint32_t) isr_10, 0x08, 0x8E );
	kIdtSetGate( 11, (uint32_t) isr_11, 0x08, 0x8E );
	kIdtSetGate( 12, (uint32_t) isr_12, 0x08, 0x8E );
	kIdtSetGate( 13, (uint32_t) isr_13, 0x08, 0x8E );
	kIdtSetGate( 14, (uint32_t) isr_14, 0x08, 0x8E );
	kIdtSetGate( 15, (uint32_t) isr_15, 0x08, 0x8E );
	kIdtSetGate( 16, (uint32_t) isr_16, 0x08, 0x8E );
	kIdtSetGate( 17, (uint32_t) isr_17, 0x08, 0x8E );
	kIdtSetGate( 18, (uint32_t) isr_18, 0x08, 0x8E );
	kIdtSetGate( 19, (uint32_t) isr_19, 0x08, 0x8E );
	kIdtSetGate( 20, (uint32_t) isr_20, 0x08, 0x8E );
	kIdtSetGate( 21, (uint32_t) isr_21, 0x08, 0x8E );
	kIdtSetGate( 22, (uint32_t) isr_22, 0x08, 0x8E );
	kIdtSetGate( 23, (uint32_t) isr_23, 0x08, 0x8E );
	kIdtSetGate( 24, (uint32_t) isr_24, 0x08, 0x8E );
	kIdtSetGate( 25, (uint32_t) isr_25, 0x08, 0x8E );
	kIdtSetGate( 26, (uint32_t) isr_26, 0x08, 0x8E );
	kIdtSetGate( 27, (uint32_t) isr_27, 0x08, 0x8E );
	kIdtSetGate( 28, (uint32_t) isr_28, 0x08, 0x8E );
	kIdtSetGate( 29, (uint32_t) isr_29, 0x08, 0x8E );
	kIdtSetGate( 30, (uint32_t) isr_30, 0x08, 0x8E );
	kIdtSetGate( 31, (uint32_t) isr_31, 0x08, 0x8E );
	kIdtSetGate( 128, (uint32_t) isr_128, 0x08, 0x8E );

	// flush the IDT
	idt_flush( (uint32_t) &kIdtPtr );
}
